package com.xuelang.pipeline.app.application.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.xuelang.hiforce.base.tracing.TracingUtils;
import com.xuelang.jadp.client.sys.dto.NgacAssociateDTO;
import com.xuelang.jadp.client.sys.dto.UserInfoDTO;
import com.xuelang.jadp.client.sys.enums.DeleteFlag;
import com.xuelang.jadp.client.sys.enums.ResourceTypeConstant;
import com.xuelang.pipeline.app.application.ApplicationService;
import com.xuelang.pipeline.app.application.ComponentService;
import com.xuelang.pipeline.app.application.converter.ApplicationDTOToApplicationComConverter;
import com.xuelang.pipeline.app.application.converter.ApplicationDTOToApplicationConverter;
import com.xuelang.pipeline.app.application.converter.ComponentDTOToComponentConverter;
import com.xuelang.pipeline.app.project.ProjectService;
import com.xuelang.pipeline.app.resource.request.NgacAssociateXO;
import com.xuelang.pipeline.client.application.dto.*;
import com.xuelang.pipeline.client.common.constant.Constant;
import com.xuelang.pipeline.client.common.request.PageParam;
import com.xuelang.pipeline.client.common.result.PageRecord;
import com.xuelang.pipeline.client.common.util.BizAssert;
import com.xuelang.pipeline.client.pipeline.dto.PipelineInstanceQuery;
import com.xuelang.pipeline.client.pipeline.dto.PipelineQuery;
import com.xuelang.pipeline.client.project.dto.ProjectDTO;
import com.xuelang.pipeline.client.resource.dto.EnvironmentQuery;
import com.xuelang.pipeline.client.resource.enums.EnvironmentEnum;
import com.xuelang.pipeline.domain.application.Application;
import com.xuelang.pipeline.domain.application.Component;
import com.xuelang.pipeline.domain.application.service.ApplicationDomainService;
import com.xuelang.pipeline.domain.application.service.ComponentDomainService;
import com.xuelang.pipeline.domain.application.service.TraitDomainService;
import com.xuelang.pipeline.domain.pipeline.Pipeline;
import com.xuelang.pipeline.domain.pipeline.PipelineInstance;
import com.xuelang.pipeline.domain.pipeline.service.*;
import com.xuelang.pipeline.domain.resource.Environment;
import com.xuelang.pipeline.domain.resource.Space;
import com.xuelang.pipeline.domain.resource.service.EnvironmentDomainService;
import com.xuelang.pipeline.domain.resource.service.SpaceDomainService;
import com.xuelang.pipeline.domain.task.service.TaskDomainService;
import com.xuelang.pipeline.domain.task.service.TaskInstanceDomainService;
import com.xuelang.sys.app.sys.NgacManagerService;
import com.xuelang.sys.app.sys.UserManagerService;
import com.xuelang.sys.app.sys.utils.UserContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 应用服务实现类
 *
 * @author liuyuan.ly
 * @since 2024/5/14 9:52
 */
@Slf4j
@Service
public class ApplicationServiceImpl implements ApplicationService {

    @Autowired
    ApplicationDomainService applicationDomainService;
    @Autowired
    ComponentDomainService componentDomainService;
    @Autowired
    EnvironmentDomainService environmentDomainService;
    @Autowired
    SpaceDomainService spaceDomainService;
    @Autowired
    TraitDomainService traitDomainService;
    @Autowired
    PipelineTagDomainService pipelineTagDomainService;
    @Autowired
    PipelineGroupDomainService pipelineGroupDomainService;
    @Autowired
    TriggerSettingDomainService triggerSettingDomainService;
    @Autowired
    VariableSettingDomainService variableSettingDomainService;
    @Autowired
    CacheSettingDomainService cacheSettingDomainService;
    @Autowired
    TaskDomainService taskDomainService;
    @Autowired
    TaskInstanceDomainService taskInstanceDomainService;
    @Autowired
    DeploymentUnitDomainService deploymentUnitDomainService;
    @Autowired
    PipelineInstanceDomainService pipelineInstanceDomainService;
    @Autowired
    PipelineDomainService pipelineDomainService;
    @Autowired
    private NgacManagerService ngacManagerService;
    @Autowired
    private UserManagerService userManagerService;
    @Autowired
    private ProjectService projectService;

    @Override
    public PageRecord<ApplicationDTO> pageList(PageParam<ApplicationQuery> dtoPageParam) {
        ApplicationQuery condition = dtoPageParam.getCondition();
        condition = condition == null ? new ApplicationQuery() : condition;
        PageRecord<Application> applicationPageRecord = applicationDomainService.pageList(
                dtoPageParam.getCurrentPage(),
                dtoPageParam.getPageSize(),
                condition);
        return new PageRecord<>(
                applicationPageRecord.getCurrentPage(),
                applicationPageRecord.getPageSize(),
                applicationPageRecord.getTotalCount(),
                applicationPageRecord.getTotalPages(),
                applicationPageRecord.getRecords().stream().map(ApplicationDTOToApplicationConverter.INSTANCE::applicationToApplicationDTO).collect(Collectors.toList()));
    }

    @Override
    public PageRecord<MyApplicationDTO> pageMyApps(PageParam<ApplicationQuery> dtoPageParam) {
        // 查询当前用户是哪些应用的管理员
        NgacAssociateDTO ngacAssociateDTO = new NgacAssociateDTO ();
        ngacAssociateDTO.setObjectType(ResourceTypeConstant.APP);// 资源类型
        ngacAssociateDTO.setTargetUser(TracingUtils.getUserId());// 授权用户
        List<NgacAssociateDTO> ngacAssociateList = ngacManagerService.findNgacAssociate(ngacAssociateDTO);
        if (CollectionUtils.isEmpty(ngacAssociateList)) {
            return new PageRecord<>(
                    dtoPageParam.getCurrentPage(),
                    dtoPageParam.getPageSize(),
                    0L,
                    0L,
                    null);
        }
        List<String> appCodeList = ngacAssociateList.stream().map(NgacAssociateDTO::getObjectId).collect(Collectors.toList());
        ApplicationQuery condition = dtoPageParam.getCondition();
        if (Objects.isNull(condition)) {
            condition = new ApplicationQuery();
        }
        condition.setCodeList(appCodeList);
        PageRecord<ApplicationDTO> applicationDTOPageRecord = pageList(dtoPageParam);

        return new PageRecord<>(
                applicationDTOPageRecord.getCurrentPage(),
                applicationDTOPageRecord.getPageSize(),
                applicationDTOPageRecord.getTotalCount(),
                applicationDTOPageRecord.getTotalPages(),
                applicationDTOPageRecord.getRecords().stream().map(this::convertToMyApp).collect(Collectors.toList()));
    }

    /**
     * 转换为我的流水线DTO
     * @param applicationDTO
     * @return
     */
    private MyApplicationDTO convertToMyApp(ApplicationDTO applicationDTO){
        String appCode = applicationDTO.getCode();

        MyApplicationDTO result = new MyApplicationDTO();
        result.setCode(appCode);
        result.setName(applicationDTO.getName());
        result.setCreatorId(applicationDTO.getCreatorId());
        result.setCreator(applicationDTO.getCreator());
        result.setCreateTime(applicationDTO.getCreateTime());

        // 查询环境数量
        EnvironmentQuery queryEnv = new EnvironmentQuery();
        queryEnv.setApplicationCode(appCode);
        List<Environment> envList = environmentDomainService.list(queryEnv);
        if(CollectionUtils.isNotEmpty(envList)) {
            result.setEnvNum(envList.size());
        }else{
            result.setEnvNum(0);
        }

        // 查询组件数量
        ComponentQuery queryComp = new ComponentQuery();
        queryComp.setApplicationCode(appCode);
        List<Component> componentList = componentDomainService.list(queryComp);
        if(CollectionUtils.isNotEmpty(componentList)) {
            result.setCompNum(componentList.size());
        }else{
            result.setCompNum(0);
        }

        // 查询流水线数量
        PipelineQuery queryPipeline = new PipelineQuery();
        queryPipeline.setApplicationCode(appCode);
        List<Pipeline> pipelineList = pipelineDomainService.list(queryPipeline);
        if(CollectionUtils.isNotEmpty(pipelineList)) {
            result.setPipelineNum(pipelineList.size());
        }else{
            result.setPipelineNum(0);
        }

        // 查询流水线实例数量
        PipelineInstanceQuery queryPipelineInstance = new PipelineInstanceQuery();
        queryPipelineInstance.setApplicationCode(appCode);
        List<PipelineInstance> pipelineInstanceList = pipelineInstanceDomainService.listByQuery(queryPipelineInstance);
        if(CollectionUtils.isNotEmpty(pipelineInstanceList)) {
            result.setPipelineInstanceNum(pipelineInstanceList.size());
        }else{
            result.setPipelineInstanceNum(0);
        }

        return result;
    }

    @Override
    public List<ApplicationComponentDTO> listWithComponent(ApplicationQuery applicationQuery) {
        log.info(">>>>ApplicationServiceImpl.listWithComponent.入参>>>{}", JSON.toJSONString(applicationQuery));
        List<ApplicationComponentDTO> list = list(applicationQuery).stream().map(ApplicationDTOToApplicationComConverter.INSTANCE::applicationDTOToApplicationCom).collect(Collectors.toList());;
        list.forEach(applicationComponentDTO -> {
            List<Component> componentList =  componentDomainService.list(ComponentQuery.builder().applicationCode(applicationComponentDTO.getCode()).build());
            applicationComponentDTO.setComponents(componentList.stream().map(ComponentDTOToComponentConverter.INSTANCE::componentToComponentDTO).collect(Collectors.toList()));
        });
        log.info(">>>>ApplicationServiceImpl.listWithComponent.响应>>>{}", JSON.toJSONString(applicationQuery));
        return list;
    }

    @Override
    public List<ApplicationComponentDTO> applicationListWithComponentPermissions(ApplicationQuery applicationQuery) {
        List<ApplicationComponentDTO> applicationComponentList = listWithComponent(applicationQuery);
        if (applicationComponentList == null || applicationComponentList.size() == 0) {
            return Collections.emptyList();
        }

        // 查询当前用户应有的组件和应用权限
        List<NgacAssociateDTO> userAppNgacList = null;
        List<NgacAssociateDTO> userAppComponentList = null;
        {
            NgacAssociateDTO ngacAssociateDTO = new NgacAssociateDTO();
            ngacAssociateDTO.setObjectType(ResourceTypeConstant.APP);
            ngacAssociateDTO.setTargetUser(UserContextUtils.getUserId());
            userAppNgacList = ngacManagerService.findNgacAssociate(ngacAssociateDTO);
            ngacAssociateDTO.setObjectType(ResourceTypeConstant.COMPONENT);
            userAppComponentList = ngacManagerService.findNgacAssociate(ngacAssociateDTO);
        }

        // 处理组件权限
        if (userAppComponentList != null && userAppComponentList.size() > 0) {
            for (ApplicationComponentDTO applicationComponentDTO : applicationComponentList) {
                if (applicationComponentDTO.getComponents() != null && applicationComponentDTO.getComponents().size() > 0) {
                    for (ComponentDTO component : applicationComponentDTO.getComponents()) {
                        NgacAssociateDTO componentNgac = userAppComponentList.stream().filter(e -> e.getObjectId().equalsIgnoreCase(component.getCode())).findAny().orElse(null);
                        if (componentNgac != null && StringUtils.isNotBlank(componentNgac.getUserAttribute()) && componentNgac.getUserAttribute().contains("管理者")) {
                            // 设置应用权限
                            applicationComponentDTO.setReadStatus(DeleteFlag.NOT_DELETE);
                            applicationComponentDTO.setWriteStatus(DeleteFlag.DELETE);
                            // 设置组件权限
                            component.setReadStatus(DeleteFlag.NOT_DELETE);
                            component.setWriteStatus(DeleteFlag.NOT_DELETE);
                        }else if (componentNgac != null && StringUtils.isNotBlank(componentNgac.getUserAttribute()) && componentNgac.getUserAttribute().contains("开发者")) {
                            // 设置应用权限
                            applicationComponentDTO.setReadStatus(DeleteFlag.NOT_DELETE);
                            applicationComponentDTO.setWriteStatus(DeleteFlag.DELETE);
                            // 设置组件权限
                            component.setReadStatus(DeleteFlag.NOT_DELETE);
                            component.setWriteStatus(DeleteFlag.DELETE);
                        }
                    }
                }
            }
        }

        // 处理应用权限
        if (userAppNgacList != null && userAppNgacList.size() > 0) {
            List<NgacAssociateDTO> finalUserAppNgacList = userAppNgacList;
            applicationComponentList.stream().forEach(e ->{
                NgacAssociateDTO ngacAssociateDTO = finalUserAppNgacList.stream().filter(e2 -> e2.getObjectId().equalsIgnoreCase(e.getCode())).findAny().orElse(null);
                if (ngacAssociateDTO != null) {
                    // 设置可读可写
                    e.setReadStatus(DeleteFlag.NOT_DELETE);
                    e.setWriteStatus(DeleteFlag.NOT_DELETE);
                    if(e.getComponents() != null && e.getComponents().size() >0){
                        e.getComponents().forEach(e3 -> {
                            // 设置可读可写
                            e3.setReadStatus(DeleteFlag.NOT_DELETE);
                            e3.setWriteStatus(DeleteFlag.NOT_DELETE);
                        });
                    }
                }
            });
        }

        // 删除多余权限
        Iterator<ApplicationComponentDTO> iterator = applicationComponentList.iterator();
        while (iterator.hasNext()) {
            ApplicationComponentDTO item = iterator.next();
            if (item.getReadStatus() != DeleteFlag.NOT_DELETE) {
                iterator.remove(); // 使用迭代器的remove方法
            }
            // 处理组件
            if (item.getComponents() != null && item.getComponents().size() > 0) {
                Iterator<ComponentDTO> compIterator = item.getComponents().iterator();
                while (compIterator.hasNext()) {
                    ComponentDTO compItem = compIterator.next();
                    if (compItem.getReadStatus() != DeleteFlag.NOT_DELETE) {
                        compIterator.remove();
                    }
                }
            }
        }
        return applicationComponentList;
    }

    @Override
    public ApplicationComponentDTO query(String code) {
        BizAssert.notNull(code, "应用编码不能为空");
        Application application = applicationDomainService.query(code);
        ApplicationDTO applicationDTO = ApplicationDTOToApplicationConverter.INSTANCE.applicationToApplicationDTO(application);
        ProjectDTO project = projectService.findProjectByCode(applicationDTO.getProjectCode());
        if (Objects.nonNull(project)) {
            applicationDTO.setProjectName(project.getProjectName());
        }
        UserInfoDTO creator = userManagerService.getUserById(application.getCreatorId());
        if(Objects.nonNull(creator)) {
            applicationDTO.setCreator(creator.getRealName());
        }else {
            applicationDTO.setCreator(Constant.UNKNOWN_USER);
        }
        ApplicationComponentDTO applicationComponentDTO = ApplicationDTOToApplicationComConverter.INSTANCE.applicationDTOToApplicationCom(applicationDTO);
        List<Component> componentList = componentDomainService.list(ComponentQuery.builder().applicationCode(code).build());
        applicationComponentDTO.setComponents(componentList.stream().map(ComponentDTOToComponentConverter.INSTANCE::componentToComponentDTO).collect(Collectors.toList()));
        return applicationComponentDTO;
    }

    @Override
    public List<ApplicationDTO> list(ApplicationQuery applicationQuery) {
        return applicationDomainService.list(applicationQuery).stream().map(ApplicationDTOToApplicationConverter.INSTANCE::applicationToApplicationDTO).collect(Collectors.toList());
    }

    @Override
    public ApplicationDTO queryByKeyword(String keyword) {
        return null;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(ApplicationDTO applicationDTO) {
        BizAssert.notNull(applicationDTO.getCode(), "应用编码不能为空");
        BizAssert.notNull(applicationDTO.getName(), "应用名称不能为空");
        Application application = ApplicationDTOToApplicationConverter.INSTANCE.applicationDTOToApplication(applicationDTO);
        boolean saveApplication = applicationDomainService.save(application);
        if (saveApplication) {
            // 将当前用户设置为管理员
            NgacAssociateDTO ngacAssociate = new NgacAssociateDTO();
            ngacAssociate.setObjectId(applicationDTO.getCode());
            ngacAssociate.setObjectType(NgacAssociateXO.ObjectTypeEnum.app.name());
            ngacAssociate.setTargetUser(TracingUtils.getUserId());  
            ngacAssociate.setUserAttribute(NgacAssociateXO.UserAttribute.builder()
                    .userName(TracingUtils.getUserName())
                    .role(NgacAssociateXO.RoleIdEnum.manager.name())
                    .roleName(NgacAssociateXO.RoleIdEnum.manager.getDescription())
                    .build()
                    .toString());
            ngacManagerService.saveNgacAssociate(ngacAssociate);
        }
        return saveApplication;
    }

    @Override
    public Boolean update(ApplicationDTO applicationDTO) {
        BizAssert.notNull(applicationDTO.getCode(), "应用编码不能为空");
        Application application = ApplicationDTOToApplicationConverter.INSTANCE.applicationDTOToApplication(applicationDTO);
        return applicationDomainService.update(application);
    }

    @Autowired
    ComponentService componentService;
    @Override
    public Boolean delete(String code) {
        BizAssert.notNull(code, "应用编码不能为空");
        boolean deleteResult = applicationDomainService.delete(Application.builder().code(code).build());
        if (deleteResult) {
            // 删除应用下的组件，级联删除组件相关资源
            Optional.ofNullable(componentDomainService.list(ComponentQuery.builder().applicationCode(code).build()))
                    .ifPresent(componentList -> componentList.forEach(component -> componentService.delete(component.getLabel())));

            // 删除应用下的环境
            environmentDomainService.deleteByApplicationCode(code);

            // 删除应用权限
            NgacAssociateDTO ngacAssociate = new NgacAssociateDTO();
            ngacAssociate.setObjectId(code);
            ngacAssociate.setObjectType(NgacAssociateXO.ObjectTypeEnum.app.name());
//            ngacAssociate.setTargetUser(TracingUtils.getUserId());
            ngacManagerService.removeNgacAssociate(ngacAssociate);
        }
        return deleteResult;
    }

}
